﻿using System;
using Microsoft.Lync.Model;
using System.Windows.Forms;
using WindowsFormDemo;

namespace WindowsFormDemo　　
{
    /// <summary>
    /// This class handles signing the user into Lync and handling or bubbling LyncClient platform events to calling code.
    /// </summary>
    class UserSignIn
    {
        #region "グローバル変数"

        /// <summary>
        /// Lyncクライアントにイニシャライズする
        /// </summary>
        private Boolean _thisProcessInitializedLync = false;

        /// <summary>
        /// Lyncのクライアントプラットフォーム
        /// </summary>
        Microsoft.Lync.Model.LyncClient _LyncClient;

        /// <summary>
        /// アカウントUri
        /// </summary>
        string _UserUri;

        #endregion

        #region "デリゲート"

        /// <summary>
        /// サインイン中にカーソル表示する
        /// </summary>
        public delegate void SetWindowCursorDelegate(Cursor newCursor);
        public event SetWindowCursorDelegate SetWindowCursor;

        /// <summary>
        /// エラー状況と親画面閉じる
        /// </summary>
        public delegate void CloseAppConditionDelegate();
        public event CloseAppConditionDelegate CloseAppConditionHit;

        /// <summary>
        /// Lyncクライアントにサインインする
        /// </summary>
        public delegate void UserIsSignedInDelegate(LyncClient lyncClient);
        public event UserIsSignedInDelegate UserIsSignedIn;

        /// <summary>
        /// クライアント状況変更する
        /// </summary>
        public delegate void ClientStateChangedDelegate(string newState);
        public event ClientStateChangedDelegate ClientStateChanged;
        #endregion

        #region "Get、Set"
        public Microsoft.Lync.Model.LyncClient Client
        {
            get
            {
                return _LyncClient;
            }
        }

        public Boolean ThisProcessInitializedLync
        {
            get
            {
                return _thisProcessInitializedLync;
            }
        }
        #endregion

        #region "プライベート機能"
        /// <summary>
        /// UI SuppressionモードでLyncクライアントをイニシャライズする
        /// </summary>
        internal void StartUpLync()
        {
            try
            {
                if (_LyncClient == null)
                {
                    _LyncClient = LyncClient.GetClient();
                }
                
                //Lyncクライアントの現在のステータスを表示
                if (ClientStateChanged != null)
                {
                    ClientStateChanged(_LyncClient.State.ToString());
                }

                //Lyncクライアントのエベント追加
                _LyncClient.StateChanged += _LyncClient_StateChanged;
                _LyncClient.SignInDelayed += _LyncClient_SignInDelayed;
                _LyncClient.CredentialRequested += _LyncClient_CredentialRequested;

                //UI Suppressionモードでサインインする為
                if (_LyncClient.State == ClientState.Uninitialized)
                {
                    _LyncClient.BeginInitialize(
                        (ar) =>
                        {
                            _LyncClient.EndInitialize(ar);
                            _thisProcessInitializedLync = true;
                        },
                        null);
                }

                else if (_LyncClient.State == ClientState.SignedIn)
                {
                    if (UserIsSignedIn != null)
                    {
                        UserIsSignedIn(_LyncClient);
                    }

                }
               
                else if (_LyncClient.State == ClientState.SignedOut)
                {
                    SignUserIn();
                }
                else if (_LyncClient.State == ClientState.SigningIn)
                {
                    if (MessageBox.Show(
                        "サインイン中です。待って続行しますか?",
                        "サインインのディレイ ",
                        MessageBoxButtons.YesNo,
                        MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                    {
                        if (CloseAppConditionHit != null)
                        {
                            CloseAppConditionHit();
                        }

                    }
                }
            }
            catch (NotInitializedException ni)
            {
                MessageBox.Show(
                    "Lyncクライアントに接続できませんので画面を閉じます。", 
                    "Lyncクライアントエラー", 
                    MessageBoxButtons.OK, MessageBoxIcon.Hand);

                if (CloseAppConditionHit != null)
                {
                    CloseAppConditionHit();
                }
                //otherwise, throw the exception.
                else
                {
                    throw ni;
                }

            }
            catch (ClientNotFoundException cnf)
            {
                MessageBox.Show(
                    "Lyncクライアントが実行できませんので画面をとじます。", 
                    "Lyncクライアントエラー", 
                    MessageBoxButtons.OK, MessageBoxIcon.Hand);
                
                if (CloseAppConditionHit != null)
                {
                    CloseAppConditionHit();
                }
                else
                {
                    throw cnf;
                }

            }
            catch (Exception exc)
            {
                MessageBox.Show(
                    "Lyncクライアントに接続できません: " +
                    exc.Message, "Lyncクライアントエラー",
                    MessageBoxButtons.OK, MessageBoxIcon.Hand);
                
                if (CloseAppConditionHit != null)
                {
                    CloseAppConditionHit();
                }
                else
                {
                    throw exc;
                }

            }
        }

        /// <summary>
        /// UI SuppressionモードでLyncクライアントにサインする
        /// </summary>
        internal void SignUserIn()
        {
            //サインイン中にカーソル表示する
            //sign in to complete
            if (SetWindowCursor != null)
            {
                SetWindowCursor(Cursors.WaitCursor);
            }

            //サインインするためアカウント情報取得
            string userUri = string.Empty;
            string userPassword = string.Empty;

            SignInCreds getCreds;
            getCreds = new SignInCreds("Sign in");
            if (getCreds.ShowDialog() == DialogResult.OK)
            {
                userUri = getCreds.UserName;
                userPassword = getCreds.Password;
                getCreds.Close();
            }

            _UserUri = userUri;
            _LyncClient.BeginSignIn(
                userUri,
                userUri,
                userPassword,
                (ar) =>
                {
                    try
                    {
                        _LyncClient.EndSignIn(ar);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(
                            "ユーザーサインする時に、エラーが発生しました。"+ex.Message,
                            "サインエラー",
                            MessageBoxButtons.OK);
                    }
                },
                null);
        }
        #endregion

        #region "クライアントエベントハンドラ"
        /// <summary>
        /// ユーザーのアカウント認証情報取得してサインインする
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">CredentialRequestedEventArgs</param>
        void _LyncClient_CredentialRequested(object sender, CredentialRequestedEventArgs e)
        {
            if (e.Type == CredentialRequestedType.LyncAutodiscover)
            {
                try
                {
                    _LyncClient.BeginSignOut((ar) =>
                    {
                        _LyncClient.EndSignOut(ar);
                        SignUserIn();

                    }, null);
                }
                catch (Exception ex)
                {
                    if (SetWindowCursor != null)
                    {
                        SetWindowCursor(Cursors.Arrow);
                    }
                    MessageBox.Show(
                        "Lyncクライアントにサインインする時、ディレイエクセプションが発生しました。 " +
                        ex.Message,
                        "Lyncクライアントにサインインディレイ",
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            else
            {
                SignInCreds getCreds;
                getCreds = new SignInCreds(e.Type.ToString());
                if (getCreds.ShowDialog() == DialogResult.OK)
                {
                    string userUri = getCreds.UserName;
                    string userPassword = getCreds.Password;
                    getCreds.Close();
                    e.Submit(userUri, userPassword, false);
                }
            }
        }

        /// <summary>
        /// サインイン時間がディレイになった場合、エラーを表示する
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">SignInDelayedEventArgs</param>
        void _LyncClient_SignInDelayed(object sender, SignInDelayedEventArgs e)
        {
            if (MessageBox.Show(
                "ディレイ開始時間 " + 
                e.EstimatedStartDelay.ToString() + 
                " ステータスコード" + 
                e.StatusCode.ToString(), 
                "Lyncクライアントにサインインディレイ", 
                MessageBoxButtons.YesNo, MessageBoxIcon.Information) == System.Windows.Forms.DialogResult.No)
            {
                if (CloseAppConditionHit != null)
                {
                    CloseAppConditionHit();
                }
            }
            else
            {
                try
                {
                    _LyncClient.BeginSignOut((ar) => { _LyncClient.EndSignOut(ar); }, null);
                }
                catch (LyncClientException lce)
                {
                    MessageBox.Show("サインアウトする時に、エラーが発生しました。 " + lce.Message);
                }
            }

        }

        /// <summary>
        /// ユーザーのサインインとサインアウト状況を取得
        /// </summary>
        /// <param name="sender">object</param>
        /// <param name="e">ClientStateChangedEventArgs</param>
        void _LyncClient_StateChanged(object sender, ClientStateChangedEventArgs e)
        {
            switch (e.NewState)
            {
                case ClientState.SignedOut:
                    if (e.OldState == ClientState.Initializing)
                    {
                        SignUserIn();
                    }
                    if (e.OldState == ClientState.SigningOut)
                    {
                        //_LyncClient.BeginShutdown((ar) =>
                        //{
                        //    _LyncClient.EndShutdown(ar);
                        //}, null);
                    }
                    break;
                case ClientState.Uninitialized:
                    if (e.OldState == ClientState.ShuttingDown)
                    {
                        _LyncClient.StateChanged -= _LyncClient_StateChanged;
                        try
                        {
                            if (CloseAppConditionHit != null)
                            {
                                CloseAppConditionHit();
                            }
                        }
                        catch (InvalidOperationException oe)
                        {
                            System.Diagnostics.Debug.WriteLine("画面を閉じる時、エラーが発生しました。 " + oe.Message);
                        }
                    }
                    break;
                case ClientState.SignedIn:
                    if (UserIsSignedIn != null)
                    {
                        UserIsSignedIn(_LyncClient);
                    }
                    break;
            }
            if (ClientStateChanged != null)
            {
                ClientStateChanged(e.NewState.ToString());
            }

        }
        #endregion

    }
}
